package cn.isjinhao.crws.util;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.Modifier;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author ISJINHAO
 * @Date 2021/3/9 19:42
 */
public class PojoClassUtil {

    private static ClassPool classPool = ClassPool.getDefault();

    private static String classNamePrefix = "TablePojo_";

    private static AtomicInteger count = new AtomicInteger(0);

    private static String packageName = "cn.isjinhao.crws.object.pojo";

    private static String rootPath = PojoClassUtil.class.getClassLoader().getResource("").getPath();

    private static Map<Long, Class> tablePojoClassMap = new ConcurrentHashMap<>();
    private static Map<Long, String> tablePojoNameMap = new ConcurrentHashMap<>();

    public static Class getClass(Map<Class, String> propertyMap) {

        Long hashCode = propertyMaphashCode(propertyMap);
        Class cachedClass = tablePojoClassMap.get(hashCode);

        if (cachedClass != null) {
            return cachedClass;
        }

        try {
            String className = packageName + "." + classNamePrefix + count.incrementAndGet();
            CtClass ctClass = classPool.makeClass(className);
            Set<Map.Entry<Class, String>> entries = propertyMap.entrySet();
            for (Map.Entry<Class, String> entry : entries) {
                Class key = entry.getKey();
                String value = entry.getValue();
                CtField f1 = CtField.make("private " + key.getName() + " " + value + ";", ctClass);
                f1.setModifiers(Modifier.PRIVATE);
                ctClass.addField(f1);
            }
            ctClass.writeFile(rootPath);
            Class<?> aClass = ctClass.toClass();
            tablePojoClassMap.put(hashCode, aClass);
            tablePojoNameMap.put(hashCode, className);
            return aClass;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Long propertyMaphashCode(Map<Class, String> propertyMap) {
        StringBuilder sb = new StringBuilder();
        Long hashcode = 0L;
        Set<Map.Entry<Class, String>> entries = propertyMap.entrySet();
        for (Map.Entry<Class, String> entry : entries) {
            Class key = entry.getKey();
            String value = entry.getValue();
            hashcode += hashcode * 31 + key.getName().hashCode() * 3 + value.hashCode() * 7;
        }
        return hashcode;
    }

    public static void main(String[] args) {
        HashMap<Class, String> classStringHashMap = new HashMap<>();
        classStringHashMap.put(String.class, "age");
        classStringHashMap.put(Date.class, "birthday");

        Class aClass = getClass(classStringHashMap);
        Class aClass2 = getClass(classStringHashMap);
    }

}